package cn.gwm.flink.streaming.strategy.vehiclepredict;

import cn.gwm.flink.streaming.constant.ChargePredictFields;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import redis.clients.jedis.JedisCluster;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;

/**
 * Author : GW00280745
 * Date : 2022/5/7 10:14
 * Description :时间处理
 * @author  :
 */
public class ChargeInfo {
    private volatile static ChargeInfo instance;
    private String tempLeftValDefault ;
    private String tempRightValDefault ;
    private String socLeftValDefault ;
    private String socRightValDefault ;
    private String[] tempDefaultTempSp;
    private String[] tempDefaultBatterSp;
    private String[] batterDefaultTempSp;
    private String[] batterDefaultSocSp;
    private String[] tempExpectTempSp;
    private String[] tempExpectBatterSp;
    private ChargeInfo(){
        tempLeftValDefault = "-20";
        tempRightValDefault = "60";
        socLeftValDefault = "0";
        socRightValDefault = "100";
        String comma = ",";
        //温升横坐标 --温度
        tempDefaultTempSp = "0,25,25".split(comma);
        //温升纵坐标 --电流
        tempDefaultBatterSp = "0,120,40".split(comma);
        //电流横坐标 --温度
        batterDefaultTempSp = "-20,55,5".split(comma);
        //电流纵坐标 --SOC
        batterDefaultSocSp = "5,100,5".split(comma);
        //#####################################期望值
        //温升横坐标 温度实际刻度--期望值
        tempExpectTempSp = "-20,55,3".split(comma);
        //温升纵坐标 电流实际刻度--期望值
        tempExpectBatterSp = "0,200,2".split(comma);
        init();
    }
    public static ChargeInfo single() {
        if (instance == null) {
            synchronized (ChargeInfo.class) {
                if (instance == null) {
                    instance = new ChargeInfo();
                }
            }
        }
        return instance;
    }

    public boolean batterDelta(String batter1,String batter2){
        try {
            BigDecimal b1 = new BigDecimal(batter1);
            BigDecimal b2 = new BigDecimal(batter2);
            BigDecimal delta = b2.subtract(b1).abs();
            BigDecimal bigDecimal = delta.divide(b1.abs(), BigDecimal.ROUND_HALF_DOWN).setScale(2);
            float v = bigDecimal.floatValue();
            float f02 = 0.2f;
            if (v>f02){
                return true;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }
    /**
     * @description: 时间差 tid2 - tid1
     * @author:  GW00280745
     * @date: 2022/5/7 11:18
     * @param: tid2 减数
     * @param: tid1 被减数
     * @return: java.lang.Long 时间差 单位s
     **/
    public Long diff(String tid2,String tid1){
        try {

            long l1 = DateUtils.parseDate(tid1, ChargePredictFields.ins().timeFormat).getTime();
            long l2 = DateUtils.parseDate(tid2, ChargePredictFields.ins().timeFormat).getTime();
            return l2 - l1;
        }catch (ParseException pe){
            pe.printStackTrace();
        }
        return null;
    }
    public Long diffL(Long tid2,Long tid1){
        try {
            long l1 = DateUtils.parseDate(tid1.toString(), ChargePredictFields.ins().timeFormat).getTime();
            long l2 = DateUtils.parseDate(tid2.toString(), ChargePredictFields.ins().timeFormat).getTime();
            return l2 - l1;
        }catch (ParseException pe){
            pe.printStackTrace();
        }
        return null;
    }
    /**
     * @description: 电池包温度处理规则 ---
     *  delta = max - min
     *  if delta <= 5 then avg
     *  if delta > 5 and min > 20 then max
     *  if delta > 5 and min <= 20 then min
     *
     * @author:  GW00280745
     * @date: 2022/5/7 11:23
     * @param: tempMaxInt
     * @param: tempMinInt
     * @return: java.lang.String
     **/
    public Integer temp(Integer tempMaxInt,Integer tempMinInt,Integer tempAvgInt){
        if (tempAvgInt == null){
            tempAvgInt = tempMaxInt;
        }
        if (tempMaxInt== null || tempMinInt == null || tempAvgInt == null) {return null;}
        int delta = tempMaxInt - tempMinInt;
        int num5= 5;
        if (delta<=num5){
            return tempAvgInt;
        }
        int num20 = 20;
        if (tempMinInt>num20){return tempMaxInt;}
        return tempMinInt;
    }
    /**
     * @description: 温度处理规则更新 只用max和min进行处理
     * @author:  GW00280745
     * @date: 2022/6/24 13:43
     * @param: tempMaxInt
     * @param: tempMinInt
     * @return: java.lang.Integer
     **/
    public Integer temp(Integer tempMaxInt,Integer tempMinInt){
        int num25 =25;
        int num40 =40;
        if (tempMaxInt== null || tempMinInt == null) {
            return null;
        }else if (tempMaxInt < tempMinInt){
            return null;
        }else if (tempMaxInt >=num25 && tempMaxInt <= num40 && tempMinInt >=num25 && tempMinInt <= num40){
            return tempMinInt;
        }else if (tempMaxInt >= num25 && tempMaxInt <= num40 && tempMinInt < num25 ){
            return tempMinInt;
        }else if (tempMaxInt < num25 && tempMinInt < num25 ){
            return tempMinInt;
        }else if (tempMaxInt > num40 && tempMinInt < num25){
            return tempMinInt;
        }else if (tempMaxInt > num40 && tempMinInt > num40 ){
            return tempMaxInt;
        }else if (tempMaxInt > num40 && tempMinInt >= num25 && tempMinInt <= num40){
            return tempMaxInt;
        }else {
            return null;
        }
    }
    /**
     * @description: 百分比字符串转为数字
     * @author:  GW00280745
     * @date: 2022/5/19 13:03
     * @param: percentVal
     * @return: java.math.BigDecimal
     **/
    public BigDecimal percentVal2Int(String percentVal){
        String s = StringUtils.substringBeforeLast(percentVal, ChargePredictFields.ins().percentChar);
        BigDecimal bigDecimal = new BigDecimal(s);
        return bigDecimal;
    }
    /**
     * @description: 获取温升map坐标信息
     * @author:  GW00280745
     * @date: 2022/5/11 17:24
     * @param: line
     * @return: java.lang.String vin#cool_heat_sts#(温度范围,电流范围)
     **/
    public String axisTempAcc(JSONObject line,String batter,String temp){
        //电池包热管理状态 --cool_heat_sts
//        bms_heatreq,bms_cooltreq,temp
        String heat = line.getString(ChargePredictFields.ins().srcFieldBmsHeatReq);
        String cool = line.getString(ChargePredictFields.ins().srcFieldBmsCoolReq);
        Integer tempInt = line.getInteger(ChargePredictFields.ins().stdFieldTemp);
        if (StringUtils.isBlank(temp)){
            temp = tempInt.toString();
        }
        String heatManagerSts = tempHeatManagerSts(heat,cool,temp);
        if (StringUtils.isBlank(batter)){
            batter = line.getString(ChargePredictFields.ins().srcFieldBmsBatterCurrRm);
        }
        //横坐标 --温度
        String axisX = axisDefault(temp,Integer.parseInt(tempExpectTempSp[0]),Integer.parseInt(tempExpectTempSp[1]),Integer.parseInt(tempExpectTempSp[2]));
        line.put(ChargePredictFields.ins().stdFieldTempAccTempRange,axisX);
        //纵坐标 --电流
        String axisY = tempBatterOperator(batter,Integer.parseInt(tempExpectBatterSp[0]),Integer.parseInt(tempExpectBatterSp[1]),Integer.parseInt(tempExpectBatterSp[2]));
        line.put(ChargePredictFields.ins().stdFieldTempAccBatterRange,axisY);
        String axis = ChargePredictFields.ins().leftParentheses.concat(axisX).concat(ChargePredictFields.ins().comma).concat(axisY).concat(ChargePredictFields.ins().rightParentheses);
        //axis_group: vin#cool_heat_sts#(x,y)
        String vehicleType = line.getString(ChargePredictFields.ins().srcFieldVehicleType);
        vehicleType=StringUtils.isBlank(vehicleType)?ChargePredictFields.ins().blankStr:vehicleType;
        String batterType = line.getString(ChargePredictFields.ins().srcFieldBatterType);
        batterType = StringUtils.isBlank(batterType)?ChargePredictFields.ins().blankStr:batterType;
        String vin = line.getString(ChargePredictFields.ins().srcFieldVin);
        String key = vehicleType.concat(ChargePredictFields.ins().char3)
                .concat(batterType).concat(ChargePredictFields.ins().char3)
//                .concat(vin).concat(EndTempConstant.char3)
                .concat(heatManagerSts).concat(ChargePredictFields.ins().char3)
                .concat(axis);
//        return vin.concat(EndTempConstant.char3).concat(heatManagerSts).concat(EndTempConstant.char3).concat(axis)
        return key;
    }

    /**
     * @description: 获取电池包热管理状态
     * @author:  GW00280745
     * @date: 2022/5/11 17:43
     * @param: heat
     * @param: cool
     * @param: temp
     * @return: java.lang.String
     **/
    private String tempHeatManagerSts(String heat, String cool, String temp) {
        String heatSignal=null;
        String coolSignal=null;
        String str1="1";
        String str2="2";
        String str3="3";
        String str4="4";
        if (StringUtils.equals(heat,str1)){
            heatSignal=heat;
        }else if (StringUtils.equals(cool,str2) || StringUtils.equals(cool,str3) || StringUtils.equals(cool,str4)){
            coolSignal=cool;
        }
        //1 -- 无加热无制冷
        if (heatSignal==null && coolSignal==null){
//            return "non_heat_cool"
            return "2";
        }
        //2 -- 加热
        if (heatSignal!=null && coolSignal==null){
//            return "heat"
            return "0";
        }
        //3 -- 制冷
        if (heatSignal==null && coolSignal!=null){
//            return "cool"
            return "1";
        }
        double v = Double.parseDouble(temp);
        int num25=25;
        if (v>=num25){
            //-- 加热
//            return "heat"
            return "0";
        }else {
            //-- 制冷
//            return "cool"
            return "1";
        }
    }

    /**
     * @description: 温度值转换成坐标值
     * @author:  GW00280745
     * @date: 2022/5/11 17:56
     * @param: temp
     * @return: java.lang.String
     **/
    private String tempTempOperator(String temp) {
        return axisDefault(temp,Integer.parseInt(tempExpectTempSp[0]),Integer.parseInt(tempExpectTempSp[1]),Integer.parseInt(tempExpectTempSp[2]));
    }
    /**
     * @description: 电流值转换成坐标值
     * @author:  GW00280745
     * @date: 2022/5/11 17:56
     * @param: batterCurrent
     * @return: java.lang.String
     **/
    private String tempBatterOperator(String batterCurrent,int start ,int end,int step) {
        if (StringUtils.isBlank(batterCurrent)){
            return "";
        }
        try {
            Double.parseDouble(batterCurrent);
        }catch (NumberFormatException nfe){
            nfe.printStackTrace();
            return batterCurrent;
        }
        double v = Double.parseDouble(batterCurrent);
        double abs = Math.abs(v);
        return axisDefault(String.valueOf(abs),start,end,step);
    }
    public String axisTempAccDefault(JSONObject line,String batter,String temp){
        Integer tempInt = line.getInteger(ChargePredictFields.ins().stdFieldTemp);
        if (StringUtils.isBlank(temp)){
            temp = tempInt.toString();
        }
        if (StringUtils.isBlank(batter)){
            batter = line.getString(ChargePredictFields.ins().srcFieldBmsBatterCurrRm);
        }
        //横坐标 --温度
//        String[] tempSP = EndTempConf.getInstance().getStrVal(EndTempConstant.tempMapDefault_temp, "0,25,25").split(EndTempConstant.comma)
        String axisX = axisDefault(temp,Integer.parseInt(tempDefaultTempSp[0]),Integer.parseInt(tempDefaultTempSp[1]),Integer.parseInt(tempDefaultTempSp[2]));
//        line.put(StdFieldsConstant.stdField_tempRange,axis_x)
        //纵坐标 --电流
//        String[] batterSP = EndTempConf.getInstance().getStrVal(EndTempConstant.tempMapDefault_batter, "0,120,40").split(EndTempConstant.comma)
        String axisY = tempBatterOperator(batter,Integer.parseInt(tempDefaultBatterSp[0]),Integer.parseInt(tempDefaultBatterSp[1]),Integer.parseInt(tempDefaultBatterSp[2]));
//        line.put(StdFieldsConstant.stdField_batterRange,axis_y)
        String axis = ChargePredictFields.ins().leftParentheses.concat(axisX).concat(ChargePredictFields.ins().comma).concat(axisY).concat(ChargePredictFields.ins().rightParentheses);
        //车型
        String vehicleType = line.getString(ChargePredictFields.ins().srcFieldVehicleType);
        vehicleType=StringUtils.isBlank(vehicleType)?ChargePredictFields.ins().blankStr:vehicleType;
        //电池类型
        String batterType = line.getString(ChargePredictFields.ins().srcFieldBatterType);
        batterType = StringUtils.isBlank(batterType)?ChargePredictFields.ins().blankStr:batterType;
        //电池包状态
        String heat = line.getString(ChargePredictFields.ins().srcFieldBmsHeatReq);
        String cool = line.getString(ChargePredictFields.ins().srcFieldBmsCoolReq);
        String heatManagerSts = tempHeatManagerSts(heat,cool,temp);
        //字符串拼接
        String key = getVehicleType(vehicleType).toString().concat(ChargePredictFields.ins().char3)
                .concat(getBatterType(batterType).toString()).concat(ChargePredictFields.ins().char3)
                .concat(heatManagerSts).concat(ChargePredictFields.ins().char3)
                .concat(axis);
        return key;
    }
    private Map<String,Integer> vehicleNameMap;
    private Map<String,Integer> batterNameMap;
    private void init(){
        vehicleNameMap = new HashMap(16);
        vehicleNameMap.put("ES13",1);

        batterNameMap = new HashMap(16);
        batterNameMap.put("磷酸铁锂电池",1);
    }
    /**
     * @description: 将车型字符串转换成对应的数字
     *  0是默认值
     **/
    public Integer getVehicleType(String vehicleName){
        String upperCase = org.apache.commons.lang3.StringUtils.upperCase(vehicleName);
        return vehicleNameMap.getOrDefault(upperCase,0);
    }

    /**
     * @description: 将电池类型字符串转换成对应的数字
     *  0是默认值
     **/
    public Integer getBatterType(String batterName){
        return batterNameMap.getOrDefault(batterName,0);
    }
    public String axisDefault(String temp, int start, int end, int step) {
        if (StringUtils.isBlank(temp)){
            return "";
        }
        try {
            Double.parseDouble(temp);
        }catch (NumberFormatException nfe){
            nfe.printStackTrace();
            return temp;
        }
        double v = Double.parseDouble(temp);
        if (v>=end){
            return  ">=".concat(String.valueOf(end));
        }else if (v < start){
            return "<".concat(String.valueOf(start));
        }
        for (int i = start; i < end; i=i+step) {
            if (v >= i && v < i+step){
                return "[".concat(String.valueOf(i))
                        .concat(",")
                        .concat(String.valueOf(i+step))
                        .concat(")");
            }
        }
        return "";
    }
    private String tempKey = "temp";
    private String socKey = "soc";
    private String tempLeftKey = "temp_left";
    private String tempRightKey = "temp_right";
    private String socLeftKey = "soc_left";
    private String socRightKey = "soc_right";
    /**
     * @description:  计算电流map表的坐标点
     * @author:  GW00280745
     * @date: 2022/5/17 10:49
     * @param: line
     * @return:
     * @return: java.lang.String vin#obc#dc#(温度,SOC)
     **/
    public String axisBatter(JSONObject line,String soc,String temp){
        if (StringUtils.isBlank(temp)){
            temp = line.getString(ChargePredictFields.ins().stdFieldTemp);
        }
        if (StringUtils.isBlank(soc)){
            soc = line.getString(ChargePredictFields.ins().srcFieldBmsSoc);
        }
        HashMap<String, String> map = new HashMap<>(16);
        map.put(tempKey,temp);
        map.put(socKey,soc);
        map.put(tempLeftKey, tempLeftValDefault);
        map.put(tempRightKey,tempRightValDefault);
        map.put(socLeftKey,socLeftValDefault);
        map.put(socRightKey,socRightValDefault);
        String operator = batterOperator(map, line,true);
        String dcConnect = line.getString(ChargePredictFields.ins().srcFieldBmsDcConnect);
        String obcConnect = line.getString(ChargePredictFields.ins().srcFieldBmsObcConnect);
        String vehicleType = line.getString(ChargePredictFields.ins().srcFieldVehicleType);
        vehicleType=StringUtils.isBlank(vehicleType)?ChargePredictFields.ins().blankStr:vehicleType;
        String batterType = line.getString(ChargePredictFields.ins().srcFieldBatterType);
        batterType = StringUtils.isBlank(batterType)?ChargePredictFields.ins().blankStr:batterType;
        String key = vehicleType.concat(ChargePredictFields.ins().char3)
                .concat(batterType).concat(ChargePredictFields.ins().char3)
                .concat(obcConnect).concat(ChargePredictFields.ins().char3)
                .concat(dcConnect).concat(ChargePredictFields.ins().char3)
                .concat(operator)
                ;
        return key;
    }
    private String batterOperator(Map<String,String> arg, JSONObject dwsLine,boolean appendFlag){
        //横坐标 温度
        String temp = StringUtils.substringBeforeLast(arg.get(tempKey),".");
        String axisX = axisDefault(temp,-20,35,1);
        if (appendFlag){
            dwsLine.put(ChargePredictFields.ins().stdFieldBatterMapTempRange,axisX);
        }
        //纵坐标 SOC
        String soc = StringUtils.substringBeforeLast(arg.get(socKey),".");
        String axisY = axisDefault(soc,0,100,1);
        dwsLine.put(ChargePredictFields.ins().stdFieldBatterMapSocRange,axisY);
        return ChargePredictFields.ins().leftParentheses.concat(axisX).concat(ChargePredictFields.ins().comma).concat(axisY).concat(ChargePredictFields.ins().rightParentheses);
    }

    private String batterTempCal(String temp, String tempLeft, String tempRight){

        try {
            int tempI = Integer.parseInt(temp);
            int tempLeftI = Integer.parseInt(tempLeft);
            int tempRightI = Integer.parseInt(tempRight);
            if (tempI < tempLeftI){
                return String.valueOf(tempLeftI);
            }
            if (tempI>=tempRightI){
                return String.valueOf(tempRightI);
            }
            return String.valueOf(tempI);
        }catch (NumberFormatException nfe){
            nfe.printStackTrace();
        }
        return temp;
    }

    public String axisBatterDefault(JSONObject line,String soc){
        String operator = batterAxisDefault(line,soc);
        String dcConnect = line.getString(ChargePredictFields.ins().srcFieldBmsDcConnect);
        String obcConnect = line.getString(ChargePredictFields.ins().srcFieldBmsObcConnect);
        String vehicleType = line.getString(ChargePredictFields.ins().srcFieldVehicleType);
        vehicleType=StringUtils.isBlank(vehicleType)?ChargePredictFields.ins().blankStr:vehicleType;
        String batterType = line.getString(ChargePredictFields.ins().srcFieldBatterType);
        batterType = StringUtils.isBlank(batterType)?ChargePredictFields.ins().blankStr:batterType;
        String key = getVehicleType(vehicleType).toString().concat(ChargePredictFields.ins().char3)
                .concat(getVehicleType(batterType).toString()).concat(ChargePredictFields.ins().char3)
                .concat(obcConnect).concat(ChargePredictFields.ins().char3)
                .concat(dcConnect).concat(ChargePredictFields.ins().char3)
                .concat(operator)
                ;
        return key;
    }

    private String batterAxisDefault(JSONObject dwsLine,String soc){
        //横坐标 温度 default： 温度默认间隔是5度 soc默认间隔是5
        String temp = dwsLine.getString(ChargePredictFields.ins().stdFieldTemp);
//        String[] tempSP = EndTempConf.getInstance().getStrVal(EndTempConstant.batterMapDefault_temp, "-20,55,5").split(EndTempConstant.comma)
//        String axis_x = axisDefault(temp,Integer.parseInt(batterDefaultTempSP[0]),Integer.parseInt(batterDefaultTempSP[1]),Integer.parseInt(batterDefaultTempSP[2]))
        String axisX = axisDefault(temp,Integer.parseInt(batterDefaultTempSp[0]),Integer.parseInt(batterDefaultTempSp[1]),5);
        //纵坐标 SOC
//        String soc = dwsLine.getString(SrcFieldsConstant.srcField_bmsSoc)
        if (StringUtils.isBlank(soc)){
            soc = dwsLine.getString(ChargePredictFields.ins().srcFieldBmsSoc);
        }
//        String[] socSP = EndTempConf.getInstance().getStrVal(EndTempConstant.batterMapDefault_soc, "5,100,5").split(EndTempConstant.comma)
//        String axis_y = axisDefault(soc,Integer.parseInt(batterDefaultSocSP[0]),Integer.parseInt(batterDefaultSocSP[1]),Integer.parseInt(batterDefaultSocSP[2]))
        String axisY = axisDefault(soc,Integer.parseInt(batterDefaultSocSp[0]),Integer.parseInt(batterDefaultSocSp[1]),5);
        return ChargePredictFields.ins().leftParentheses.concat(axisX).concat(ChargePredictFields.ins().comma).concat(axisY).concat(ChargePredictFields.ins().rightParentheses);
    }

    public String getRedisHvalNoDefault(JedisCluster jedis, String hashKey, String fieldKey){
        String s = redisHvalNoDefault(jedis, hashKey, fieldKey);
        try {
            JSONObject.parseObject(s);
            return s;
        }catch (JSONException je){
            String format = String.format("jedis获取失败:%s, hashKey: %s , fieldKey: %s ", s, hashKey, fieldKey);
            int num3=3;
            for (int i = 0; i < num3; i++) {
                try {
                    String sTmp = redisHvalNoDefault(jedis, hashKey, fieldKey);
                    JSONObject.parseObject(sTmp);
                    return sTmp;
                }catch (Exception e){
                    continue;
                }
            }
        }
        return null;
    }
    private String redisHvalNoDefault(JedisCluster jedis, String hashKey, String fieldKey){
        if (StringUtils.isBlank(hashKey) || StringUtils.isBlank(fieldKey)){
            return null;
        }
        return jedis.hget(hashKey,fieldKey);
    }

    public String getRedisHval(JedisCluster jedis, String hashKey, String fieldKey){
        String s = redisHval(jedis, hashKey, fieldKey);
        try {
            JSONObject.parseObject(s);
            return s;
        }catch (JSONException je){
            String format = String.format("jedis获取失败:%s, hashKey: %s , fieldKey: %s ", s, hashKey, fieldKey);
            System.out.println(format);
            int num3=3;
            for (int i = 0; i < num3; i++) {
                try {
                    String sTmp = redisHval(jedis, hashKey, fieldKey);
                    JSONObject.parseObject(sTmp);
                    return sTmp;
                }catch (Exception e){
                    continue;
                }
            }
        }
        return null;
    }
    private String redisHval(JedisCluster jedis, String hashKey, String fieldKey){
        if (StringUtils.isBlank(hashKey) || StringUtils.isBlank(fieldKey)){
            return null;
        }
        String temp = fieldKey;
        Boolean exists = jedis.hexists(hashKey, fieldKey);
        if (!exists){
            // 通过vin查不到数据时，可以查找同款车型
            Set<String> hkeys = jedis.hkeys(hashKey);
            for (String hkey : hkeys) {
                if (StringUtils.isBlank(hkey)){
                    continue;
                }
                if (StringUtils.equalsIgnoreCase(fieldKey,hkey)){
                    continue;
                }
                fieldKey=hkey;
                break;
            }
            System.out.println(String.format("%s,jedis获取失败:fieldKey不存在:%s,查询同款车型数据: %s ",hashKey,temp,fieldKey));
        }
        String s = jedis.hget(hashKey,fieldKey);
        if (StringUtils.isBlank(s)){
            return s;
        }
        return s    ;
    }
    /**
     * @description: 电流map查询顺序：bms:charge_end_temp:batter:
     *      vehicleType#batterType#obcConnect#dcConnect#(温度,soc)
     * @author:  GW00280745
     * @date: 2022/7/5 10:56
     * @param:
     * @param: jedis
     * @param: hashKey
     * @param: fieldKey
     * @return:
     * @return: java.lang.String
     **/
    public String getRedisHvalBatter(JedisCluster jedis, String hashKey, String fieldKey){
        if (StringUtils.isBlank(hashKey) || StringUtils.isBlank(fieldKey)){
            return null;
        }
        String temp = fieldKey;
        Boolean exists = jedis.hexists(hashKey, fieldKey);
        if (!exists){
            // 通过vin查不到数据时，可以查找同款车型
            Set<String> hkeys = jedis.hkeys(hashKey);
            for (String hkey : hkeys) {
                if (StringUtils.isBlank(hkey)){
                    continue;
                }
                if (StringUtils.equalsIgnoreCase(fieldKey,hkey)){
                    continue;
                }
                fieldKey=hkey;
                break;
            }
            System.out.println(String.format("%s,jedis获取失败:fieldKey不存在:%s,查询同款车型数据: %s ",hashKey,temp,fieldKey));
        }
        String s = jedis.hget(hashKey,fieldKey);
        if (StringUtils.isBlank(s)){
            return s;
        }
        try {
            JSONObject.parseObject(s);
            return s;
        }catch (JSONException je){
            String format = String.format("jedis获取失败:%s, hashKey: %s , fieldKey: %s ", s, hashKey, fieldKey);
            System.out.println(format);
            return getRedisHval(jedis,hashKey,fieldKey);
        }
    }
    /**
     * @description: 温升速率读取规则： 车型+加热+axis+vin > 车型+无加热+axis+vin > 车型+加热+axis+another vin > 车型+无加热+axis+another vin > axis + anyone vin
     *
     * @author:  GW00280745
     * @date: 2022/7/5 8:18
     * @param:
     * @param: jedis
     * @param: hashKey
     * @param: fieldKey
     * @return:
     * @return: java.lang.String
     **/
    public String getRedisHvalTemp(JedisCluster jedis, String hashKey, String fieldKey){
        if (StringUtils.isBlank(hashKey) || StringUtils.isBlank(fieldKey)){
            return null;
        }
        String temp = fieldKey;
        Boolean exists = jedis.hexists(hashKey, fieldKey);
        if (exists){
            return hsetVal(jedis, hashKey, fieldKey);
        }
        //bms:charge_end_temp:tempAcc:vehicleType#batterType#non_heat_cool#(温度范围,电流范围)
        String axis = StringUtils.substringAfterLast(hashKey, ChargePredictFields.ins().colon);
        String[] axisSp = axis.split(ChargePredictFields.ins().char3);
        String newAxis = axisSp[0].concat(ChargePredictFields.ins().char3)
                .concat(axisSp[1]).concat(ChargePredictFields.ins().char3)
                .concat("non_heat_cool").concat(ChargePredictFields.ins().char3)
                .concat(axisSp[3]).concat(ChargePredictFields.ins().char3);
        String newHashKey = ChargePredictFields.ins().redisNameSpaceTemp.concat(newAxis);
        //查询顺序2. 车型+无加热+axis+vin
        String abc="non_heat_cool";
        int num2=2;
        if (!StringUtils.equalsIgnoreCase(axisSp[num2],abc)){
            String newFieldKey = hkeysOne(jedis, newHashKey, fieldKey, false);
            if (StringUtils.isNotBlank(newFieldKey)){
                String s = hsetVal(jedis, newHashKey, newFieldKey);
                if (StringUtils.isNotBlank(s)){
                    return s;
                }
            }
        }
        //查询顺序3. 车型+加热+axis+another vin
        String anotherFieldKey = hkeysOne(jedis, hashKey, fieldKey, true);
        if (StringUtils.isNotBlank(anotherFieldKey)){
            String s = hsetVal(jedis, hashKey, anotherFieldKey);
            if (StringUtils.isNotBlank(s)){
                return s;
            }
        }
        //查询顺序4. 车型+无加热+axis+another vin


        if (!StringUtils.equalsIgnoreCase(axisSp[num2],abc)){
            String newFieldKey = hkeysOne(jedis, newHashKey, anotherFieldKey, false);
            if (StringUtils.isNotBlank(newFieldKey)){
                String s = hsetVal(jedis, newHashKey, newFieldKey);
                if (StringUtils.isNotBlank(s)){
                    return s;
                }
            }
        }
//        //查询顺序5. axis + anyone vin
//        String defaultHashKey = EndTempConstant.redisNameSpace_temp.concat(axis)
//        String defaultFieldKey = hkeysOne(jedis, defaultHashKey, anotherFieldKey, false)
//        if (StringUtils.isNotBlank(defaultFieldKey)){
//            String s = hsetVal(jedis, defaultHashKey, defaultFieldKey)
//            if (StringUtils.isNotBlank(s)){
//                return s
//            }
//        }
        return ChargePredictFields.ins().blankStr;
    }
    private String hkeysOne(JedisCluster jedis, String hashKey, String fieldKey,boolean isDiff){
        Set<String> hkeys = jedis.hkeys(hashKey);
        for (String hkey : hkeys) {
            if (StringUtils.isBlank(hkey)){
                continue;
            }
            if ( isDiff && StringUtils.equalsIgnoreCase(fieldKey,hkey)){
                continue;
            }
            return hkey;
        }
        return null;
    }
    private String hsetVal(JedisCluster jedis, String hashKey, String fieldKey) {
        String s = jedis.hget(hashKey, fieldKey);
        if (StringUtils.isBlank(s)){
            return s;
        }
        try {
            JSONObject.parseObject(s);
            return s;
        }catch (JSONException je){
            String format = String.format("jedis获取失败并进行无限重试:%s, hashKey: %s , fieldKey: %s ", s, hashKey, fieldKey);
            System.out.println(format);
            return hsetVal(jedis, hashKey, fieldKey);
        }
    }


    public Integer dcObc(Integer obcConnect,Integer dcConnect){
        if (obcConnect == null && dcConnect == null){
            return null;
        }
        if (obcConnect == null){
            return 0;
        }
        if (dcConnect == null){
            return 1;
        }
        if (obcConnect==0 && dcConnect==1){
            return 0;
        }else if (obcConnect == 1 && dcConnect ==0){
            return 1;
        }else {
            return 2;
        }
    }

    public String moveAvg(JSONObject mapVal,String val,JSONObject dwsLine,String startsWith,String pointField,String errField,String avgField){
        //处理当前记录的数据
        String currVal = StringUtils.substringBefore(val, ChargePredictFields.ins().char3);
        String currKey = StringUtils.substringAfter(val, ChargePredictFields.ins().char3);
        mapVal.put(currKey,currVal);
        //将更新得mapVal转成字符串返回
        ArrayList<String> list = Lists.newArrayList();
        Iterator<Map.Entry<String, Object>> iterator = mapVal.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Object> entry = iterator.next();
            String key = entry.getKey();
            Object valueObj = entry.getValue();
            if (StringUtils.startsWith(key,startsWith)){continue;}
            if (valueObj==null){continue;}
            String value = valueObj.toString();
            String line = value.concat(ChargePredictFields.ins().char3).concat(key);
            list.add(line);
        }
//        list.add(val)
        Collections.sort(list, (o1, o2) -> {
            String s1 = StringUtils.substringAfterLast(o1, ChargePredictFields.ins().char3);
            String s2 = StringUtils.substringAfterLast(o2, ChargePredictFields.ins().char3);
            return s1.compareTo(s2);
        });
        Double sum = 0d;
        int denominator = 0;
        String tmpKey = "";
        JSONObject jsonRes = new JSONObject();
        for (int i = 0; i < list.size(); i++) {
            if (denominator>=5){
                break;
            }
            String s = list.get(i);
            String accKey = StringUtils.substringAfterLast(s, ChargePredictFields.ins().char3);
            if (StringUtils.equals(accKey,tmpKey)){
                continue;
            }
            tmpKey=accKey;
            String accVal = StringUtils.substringBefore(s, ChargePredictFields.ins().char3);
            double v = Double.parseDouble(accVal);
            //如果是0也参与计算，如果是null则证明是无效值
//            if (v == 0d){continue;}
            sum += v;
            denominator ++;
            String key = StringUtils.substringAfterLast(s, ChargePredictFields.ins().char3);
            jsonRes.put(key,v);
        }
        double newAcc = sum /denominator;
        BigDecimal roundHalfUp = roundHalfUp(new BigDecimal(newAcc), 2);
        jsonRes.put(avgField,roundHalfUp);
        dwsLine.put(pointField,roundHalfUp);
        dwsLine.put(errField,ChargePredictFields.ins().zeroStr);
        return jsonRes.toJSONString();
    }
    public BigDecimal roundHalfUp(BigDecimal bigDecimal,int scaleVal) {
        if (bigDecimal == null){return bigDecimal;}
        BigDecimal scale = bigDecimal.setScale(scaleVal, BigDecimal.ROUND_HALF_UP);
        return scale;
    }
}
